
<script lang="ts" setup>
import {mitt, service} from '@/utils';
import {h, onMounted, reactive, ref, watch} from "vue";
import Uploader from './upload.vue'
import {ElMessage, ElButton} from 'element-plus'
import {View, Tickets, Refresh, Delete, Search} from "@element-plus/icons-vue";
import type Node from 'element-plus/es/components/tree/src/model/node'
import store from "@/store";

defineOptions({name: "Asn1Tools"});

interface SearchForm {
    name: string[];
    asnValue: string;
}
interface BusinessTypeCascader {
    asnData: any[];
    options: any[];
    props: { [key: string]: string };
    handle: { [key: string]: any };
}

interface FileTree {
    current: any,
    files: any[],
    handle: {[key:string]:any}
}

const {user} = store.userStore;
const uploadRef = ref()

const businessTypeRef = ref()
const form = reactive<SearchForm>({
    name: [],
    asnValue: ''
})
const cascader = reactive<BusinessTypeCascader>({
    props: {
        value: 'name',
        label: 'name',
        expandTrigger: 'hover'
    },
    options: [],
    asnData: [],
    handle: {
        init: () => {
            service.get('/asn1/view').then(({data}) => {
                // 加载并初始化业务类型数据集
                cascader.options = data;
                form.name[0] = form.name[0] || data[0].name;
                // 加载并初始化配置文件数据集
                let item = cascader.options.find(o => o.name === form.name[0]);
                cascader.asnData = item?.['asn'] || []
                form.asnValue = form.asnValue && cascader.asnData.includes(form.asnValue)? form.asnValue:cascader.asnData.first();
            })
        },
        // 业务类型发生变化
        change: () => {
            const data = cascader.options.find(item => item.name === form.name[0]);
            cascader.asnData = data?.['asn'] || [];
            form.asnValue = cascader.asnData.first();
        },
        // 删除配置文件
        deleteConfig: (asn: string) => {
            service.confirm(`确定删除[${form.name[0]}] - [${asn}],该操作不可逆?`, {
                url: '/asn1/update',
                type: 'get',
                data: {
                    name: form.name[0],
                    asn: asn,
                    delete: true
                },
                success: () => {
                    cascader.handle.init();
                }
            })
        }
    }
})

const fileTreeRef = ref();
const fileTree = reactive<FileTree>({
    current: null,
    files: [],
    handle: {
        refresh: (asn = form.asnValue) => {
            service.get('/asn1/data', {user: user?.userId, asn: asn}).then(({data}) => {
                let items: any[] = [];
                Object.keys(data||{}).forEach((key: string, index: number) => {
                    let obj = {id: 'd_' + index, label: key.slice(1), children: []}
                    obj.children = data[key].map((file: string[], id: number) => ({id: 'f_' + index + id, label: file[0], path: file[1], decode: file[2]}))
                    items.push(obj)
                })
                fileTree.files = items;
            });
        },
        // 解析数据文件
        analysis: (node: any) => {
            if (node !== null && !!node.path) {
                service.get('/asn1/analysis', {user: user?.userId, asn: form.asnValue, path: node.path})
            } else {
                ElMessage.warning('请选择需要解析的数据文件')
            }
        },
        // 删除数据文件
        delete: () => {
            let nodes = fileTreeRef.value.getCheckedNodes();
            let files = nodes.filter((node: any) => !!node.path).map((node: any) => node.path);
            if (files.length === 0) {
                ElMessage.warning('请勾选需要删除的数据文件')
            } else {
                service.confirm(`确定删除所选文件,该操作不可逆?`, {
                    url: '/asn1/remove',
                    data: {files: files},
                    success: ({code}) => {
                        if (code === 200) {
                            // 删除文件的文件中包含当前正在预览数据文件
                            let current = fileTreeRef.value.getCurrentNode();
                            if (current !== null && !!nodes.find((node: Node) => node.id === current.id)) {
                                fileTree.current = null;
                                fileTreeRef.value.setCurrentKey(null);
                                table.data = [];
                                table.start = 0;
                                table.total = 0;
                            }

                            // 半选状态的节点取消选中
                            fileTreeRef.value.getHalfCheckedNodes().forEach((node: Node) => fileTreeRef.value.setChecked(node, false, true))
                            nodes.forEach((node: Node) => fileTreeRef.value.remove(node))
                        }
                    }
                });
            }
        },
        view: (node: any) => {
            fileTree.current = node.data;
            table.data = [];
            table.start = 0;
            table.keyword = '';
            table.handle.load(node);
        }
    }
})

const columns = ref([
    { key: 'no', dataKey: `no`, width: 120, title: '行号', align: 'center'},
    { key: `content`, dataKey: `content`, title: '内容', width: '100%', align: 'center'},
    { key: 'operations', title: '操作', width: 120, align: 'center',
        cellRenderer: (data: any) => h(ElButton, {onClick: () => table.handle.viewData(data), icon: Search, circle: true})
    }
]);
const content = ref<string>('');
const table = reactive({
    loading: false,
    data: [] as any[],
    total: 0,
    start: 0,
    keyword: '',
    handle: {
        // 加载解析结果
        load: (node = fileTreeRef.value.getNode(fileTree.current)) => {
            if (node) {
                table.loading = true;
                service.get('/asn1/search', {path: node.data.path, start: table.start, keyword: table.keyword}).then(({code, data})=>{
                    if (code === 200 && data) {
                        table.data.push(...data.data)
                        table.total = data.total
                        table.start = data.start
                    }
                }).finally(() => table.loading = false)
            }
        },
        // 查找关键字
        search: () => {
            table.data = [];
            table.start = 0;
            table.handle.load();
        },
        // 滚动条到达底部时继续加载数据
        endReached: () => {
            if (table.total === table.start) {
                ElMessage.info('没有更多数据加载');
            } else {
                table.handle.load();
            }
        },
        // 数据预览
        viewData: ({rowData}: any) => {
            dialogVisible.value = true
            content.value = JSON.stringify(JSON.parse(rowData.content), null, '\t')
        }
    }
});

const dialogVisible = ref(false);


// 上传文件
const commandHandle = (command: string) => {
    if (command === 'data') {
        mitt.emit('onGlobalFileUpload', {from: '20010', owner: user?.userId, p1: form.asnValue})
    } else {
        uploadRef.value.open(form.name[0], cascader.handle.init);
    }
}

onMounted(() => cascader.handle.init())

watch(() => form.asnValue, (v) => fileTree.handle.refresh(v))
</script>
<template>
    <div class="asn-mode">
        <el-form :inline="true" :model="form" class="search-form">
            <el-form-item label="业务类型" prop="name">
                <el-cascader ref="businessTypeRef" v-model="form.name" :options="cascader.options" :props="cascader.props" @change="cascader.handle.change"/>
            </el-form-item>
            <el-form-item label="配置文件" prop="asnValue">
                <el-select v-model="form.asnValue" filterable>
                    <el-option v-for="(item, index) in cascader.asnData" :key="index" :label="item" :value="item">
                        <span style="float: left">{{ item }}</span>
                        <span style="float: right; margin-right: -12px" @click="cascader.handle.deleteConfig(item)">
                            <el-icon>
                                <svg-icon icon="icon-delete"/>
                            </el-icon>
                        </span>
                    </el-option>
                </el-select>
            </el-form-item>
            <el-form-item>
                <el-dropdown style="margin: 0 5px 0 5px;" trigger="hover" @command="commandHandle">
                    <el-button> 上传文件</el-button>
                    <template #dropdown>
                        <el-dropdown-menu style="padding-top: 10px">
                            <el-dropdown-item command="data">
                                数据文件
                            </el-dropdown-item>
                            <el-dropdown-item command="config">
                                配置文件
                            </el-dropdown-item>
                        </el-dropdown-menu>
                    </template>
                </el-dropdown>

            </el-form-item>
        </el-form>

        <div class="asn-main">
            <el-card body-style="padding: 5px 0;height: calc(100% - 55px); overflow-y: auto;">
                <template #header>
                    <span>
                        文件列表
                    </span>
                    <div>
                        <el-button @click="fileTree.handle.refresh()" :icon="Refresh" title="刷新"/>
                        <el-button @click="fileTree.handle.delete()" :icon="Delete" title="删除"/>
                    </div>

                </template>
                <el-tree ref="fileTreeRef"
                         :data="fileTree.files"
                         :default-expanded-keys="['d_0']"
                         :highlight-current="true"
                         :show-checkbox="true"
                         node-key="id">
                    <template #default="{ node, data }">
                        <span v-if="!data.path" :title="node.label">{{ node.label }}</span>
                        <div v-else class="asn-node">
                            <el-text :type="['ready', 'decode'].includes(data.decode)? 'info':data.decode === 'error'? 'danger':'success'"
                                     style="max-width: 200px" truncated>
                                {{ node.label }}
                            </el-text>
                            <div style="display: flex">
                                <el-link v-if="data.decode === 'success'" class="asn-options" title="预览/刷新" type="primary" :underline="false" :icon="View" @click="fileTree.handle.view(node)"/>
                                <el-link class="asn-options" title="解析" type="primary" :underline="false" :icon="Tickets" @click="fileTree.handle.analysis(data)"/>
                            </div>
                        </div>
                    </template>
                </el-tree>
            </el-card>

            <el-card body-style="padding: 5px 5px;height: calc(100% - 55px)">
                <template #header>
                    <div class="header">
                        <span>{{fileTree.current?.label}}</span>
                        <div>
                            <el-input v-model="table.keyword"
                                      :clearable="true"
                                      :disabled="!fileTree.current"
                                      placeholder="请输入检索关键字"
                                      style="width: 320px"
                                      @keydown.enter="table.handle.search()"/>
                            <el-button :disabled="!fileTree.current" :icon="Search" @click="table.handle.search()" style="margin-left: 5px"/>
                        </div>
                    </div>
                </template>
                <el-auto-resizer>
                    <template #default="{ height, width }">
                        <el-table-v2 :columns="columns"
                                     :data="table.data"
                                     :row-height="50"
                                     :expand-column-key="columns[0].key"
                                     :footer-height="50"
                                     :height="height"
                                     :width="width"
                                     @end-reached="table.handle.endReached">
                            <template v-if="table.loading" #overlay>
                                <div class="el-loading-mask" style="display: flex; align-items: center; justify-content: center">
                                    <el-icon :size="26" class="is-loading" color="var(--el-color-primary)">
                                        <svg-icon name="el-icon-loading"/>
                                    </el-icon>
                                </div>
                            </template>
                            <template #footer>
                                <div style="justify-content: space-between;
                                            height: 100%;
                                            background-color: var(--el-color-primary-light-7);
                                            display: flex;
                                            padding: 15px">
                                    <div>
                                        <el-link :underline="false" type="info">
                                            {{ table.keyword !== '' ? '查找：“' + table.keyword + '”,' : '' }}&nbsp;&nbsp;共计：{{ table.total }} 条记录数
                                        </el-link>
                                    </div>
                                </div>
                            </template>
                        </el-table-v2>
                    </template>
                </el-auto-resizer>
            </el-card>
        </div>

        <!--上传配置文件-->
        <uploader ref="uploadRef"/>
        <!--数据预览-->
        <el-dialog v-model="dialogVisible" title="内容" width="60%">
            <el-input v-model="content" :autosize="{ minRows: 25, maxRows: 25 }" type="textarea"/>
            <template #footer>
                <span>
                    <el-button @click="dialogVisible = false">关闭</el-button>
                </span>
            </template>
        </el-dialog>
    </div>
</template>
<style lang="scss" scoped>
.asn-mode {
    height: 100%;

    .el-tree {

        .asn-node {
            display: inline-flex;
            flex-grow: 1;
            justify-content: space-between;

            .asn-options {
                float: right;
                opacity: 0;
                transition: opacity var(--el-transition-duration);
                margin-right: 10px;
            }
        }

        .el-tree-node__children .is-current {
            .asn-options {
                opacity: 1;
            }
        }
    }

    .search-form {
        height: 60px;
        display: flex;
        align-items: center;

        .el-form-item--default {
            margin-bottom: 0;
        }

        .el-form-item:nth-child(2) {
            width: calc(var(--el-form-inline-content-width) + 62px);
        }

        .el-form-item:last-child {
            flex-grow: 1;
            margin-right: 0;
            display: flex;
            justify-content: flex-end;

            ::v-deep(.el-form-item__content) {
                flex: unset;
            }
        }
    }

    .asn-main {
        display: flex;
        height: calc(100% - 60px);
        width: 100%;
        gap: 5px;

        .el-card:first-child {
            width: 25%;

            ::v-deep(.el-card__header) {
                padding: 5px;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
        }

        .el-card:last-child {
            flex-grow: 1;

            ::v-deep(.el-card__header) {
                padding: 5px;
                display: flex;
                justify-content: end;

                .header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    width: 100%;

                    .el-input-group__append{
                        cursor: pointer;
                    }

                    .is-disabled .el-input-group__append{
                        cursor: not-allowed;
                    }
                }


            }

            ::v-deep(.el-virtual-scrollbar) {
                height: 0 !important;
            }

            ::v-deep(.el-empty) {
                height: 100%;
            }
        }


    }
}
</style>